package cn.iocoder.yudao.module.promotion.coupon.dal.mysql;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.business.basic.dao.mapper.CoreMapper;
import cn.iocoder.yudao.framework.business.basic.dao.query.CoreLambdaQueryWrapper;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
import cn.iocoder.yudao.module.api.promotion.coupon.enums.CouponStatusEnum;
import cn.iocoder.yudao.module.promotion.coupon.dal.dataobject.CouponRecordDO;
import cn.iocoder.yudao.module.promotion.coupon.vo.CouponRecordPageReqVO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.yulichang.toolkit.MPJWrappers;
import jakarta.annotation.Nullable;
import org.apache.ibatis.annotations.Mapper;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;

/**
 * 优惠劵领取记录 Mapper
 *
 * @author 芋道源码
 */
@Mapper
public interface CouponRecordMapper extends CoreMapper<CouponRecordDO> {

    default PageResult<CouponRecordDO> selectPage(CouponRecordPageReqVO reqVO) {
        return selectPage(reqVO, new CoreLambdaQueryWrapper<CouponRecordDO>()
                .eqIfPresent(CouponRecordDO::getTemplateId, reqVO.getTemplateId())
                .eqIfPresent(CouponRecordDO::getStatus, reqVO.getStatus())
                .inIfPresent(CouponRecordDO::getUserId, reqVO.getUserIds())
                .betweenIfPresent(CouponRecordDO::getCreateTime, reqVO.getCreateTime())
                .orderByDesc(CouponRecordDO::getId));
    }

    default List<CouponRecordDO> selectListByUserIdAndStatus(Long userId, @Nullable Integer status) {
        return selectList(new CoreLambdaQueryWrapper<CouponRecordDO>()
                .eq(CouponRecordDO::getUserId, userId)
                .eqIfPresent(CouponRecordDO::getStatus, status));
    }

    default List<CouponRecordDO> selectUnusedListByUserId(Long userId, @Nullable List<Integer> scopes) {
        return selectList(new CoreLambdaQueryWrapper<CouponRecordDO>()
                .eq(CouponRecordDO::getUserId, userId)
                .eqIfPresent(CouponRecordDO::getStatus, CouponStatusEnum.UNUSED.getStatus())
                .inIfPresent(CouponRecordDO::getProductScope, scopes));
    }

    default CouponRecordDO selectByIdAndUserId(Long id, Long userId) {
        return selectOne(CouponRecordDO::getId, id, CouponRecordDO::getUserId, userId);
    }

    default int delete(Long id, Collection<Integer> whereStatuses) {
        return update(null, new LambdaUpdateWrapper<CouponRecordDO>()
                .eq(CouponRecordDO::getId, id).in(CouponRecordDO::getStatus, whereStatuses)
                .set(CouponRecordDO::getDeleted, 1));
    }

    default int updateByIdAndStatus(Long id, Integer status, CouponRecordDO updateObj) {
        return update(updateObj, new LambdaUpdateWrapper<CouponRecordDO>()
                .eq(CouponRecordDO::getId, id).eq(CouponRecordDO::getStatus, status));
    }

    default Long selectCountByUserIdAndStatus(Long userId, @Nullable Integer status) {
        return selectCount(new CoreLambdaQueryWrapper<CouponRecordDO>()
                .eq(CouponRecordDO::getUserId, userId)
                .eqIfPresent(CouponRecordDO::getStatus, status));
    }

    default List<CouponRecordDO> selectListByTemplateIdAndUserId(Long templateId, Collection<Long> userIds) {
        return selectList(new CoreLambdaQueryWrapper<CouponRecordDO>()
                .eq(CouponRecordDO::getTemplateId, templateId)
                .in(CouponRecordDO::getUserId, userIds)
        );
    }

    default Map<Long, Integer> selectCountByUserIdAndTemplateIdIn(Long userId, Collection<Long> templateIds) {
        String templateIdAlias = "templateId";
        String countAlias = "count";
        List<Map<String, Object>> list = selectMaps(MPJWrappers.lambdaJoin(CouponRecordDO.class)
                .selectAs(CouponRecordDO::getTemplateId, templateIdAlias)
                .selectCount(CouponRecordDO::getId, countAlias)
                .eq(CouponRecordDO::getUserId, userId)
                .in(CouponRecordDO::getTemplateId, templateIds)
                .groupBy(CouponRecordDO::getTemplateId));
        return convertMap(list, map -> MapUtil.getLong(map, templateIdAlias), map -> MapUtil.getInt(map, countAlias));
    }

    default List<CouponRecordDO> selectListByStatusAndValidEndTimeLe(Integer status, LocalDateTime validEndTime) {
        return selectList(new CoreLambdaQueryWrapper<CouponRecordDO>()
                .eq(CouponRecordDO::getStatus, status)
                .le(CouponRecordDO::getValidEndTime, validEndTime)
        );
    }

    default Set<Long> selectTemplateIdsByUserIdAndTemplateIds(Long userId, Set<Long> templateIds) {
        if (CollUtil.isEmpty(templateIds)) {
            return new HashSet<>();
        }
        String templateIdAlias = "templateId";
        List<Map<String, Object>> maps = selectMaps(new MPJLambdaWrapperX<CouponRecordDO>()
                .selectAs(CouponRecordDO::getTemplateId, templateIdAlias)
                .eq(CouponRecordDO::getUserId, userId)
                .in(CouponRecordDO::getTemplateId, templateIds));
        if (CollUtil.isEmpty(maps)) {
            return new HashSet<>();
        }
        return maps.stream().map(map -> MapUtil.getLong(map, templateIdAlias, 0L))
                .collect(Collectors.toSet());
    }

    default CouponRecordDO selectByProductScopeValues(String verifyCode) {
        CoreLambdaQueryWrapper<CouponRecordDO> wrapper = new CoreLambdaQueryWrapper<>();
        wrapper.apply("FIND_IN_SET({0}, product_scope_values) > 0", verifyCode);
        return selectOne(wrapper);
    }

}
